/***********************************************************************

This file is part of the LidarFormat project source files.

LidarFormat is an open source library for efficiently handling 3D point 
clouds with a variable number of attributes at runtime. 


Homepage: 

http://code.google.com/p/lidarformat

Copyright:

Institut Geographique National & CEMAGREF (2009)

Author: 

Adrien Chauve

Contributors:

Nicolas David, Olivier Tournaire



LidarFormat is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

LidarFormat is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with LidarFormat.  If not, see <http://www.gnu.org/licenses/>.

***********************************************************************/


#include "LidarFormat/LidarIOFactory.h"
#include "LidarFormat/LidarDataContainer.h"

#include "BinaryPLYArchiLidarFileIO.h"

namespace Lidar
{

	void BinaryPLYArchiLidarFileIO::loadData(LidarDataContainer& lidarContainer, const XMLLidarMetaData& lidarMetaData, const XMLAttributeMetaDataContainerType& attributesDescription)
	{

		// BV: very subtle problem: windows endlines are counted double in ascii (\R\N), but not in binary (0a)
		// so under windows there will be a shift between ascii and binary positions
		// My solution: we get the data size from the xml and get the end header position from end of file based on it
		// TODO: more careful checking of xml/ply coherence
		std::ifstream fileInBin(lidarMetaData.binaryDataFileName_.c_str(), std::ios::binary);
		if(fileInBin.good())
		{
			fileInBin.seekg(0, std::ios::end);
			const int dataSize = lidarMetaData.nbPoints_*lidarContainer.pointSize();
			if(fileInBin.tellg() < dataSize)
				std::cout << "ERROR (BinaryPLYArchiLidarFileIO::loadData) binary file size " << fileInBin.tellg() << "< what xml expects: " << dataSize << std::endl;
			fileInBin.seekg(-dataSize, std::ios::end);
			std::cout << "Binary part starts at " << fileInBin.tellg() << std::endl;
			// lidarContainer.allocate(lidarMetaData.nbPoints_); // BV: do we need that ? works well without
			fileInBin.read(lidarContainer.rawData(), dataSize);
		}
		else
			throw std::logic_error("ERROR (BinaryPLYArchiLidarFileIO::loadData) binary file does not exist or cannot be accessed ! \n");
	}

	void BinaryPLYArchiLidarFileIO::save(const LidarDataContainer& lidarContainer, const std::string& binaryDataFileName)
	{
		std::ofstream fileOut(binaryDataFileName.c_str(), std::ios::binary);

		if(fileOut.good())
			fileOut.write(lidarContainer.rawData(), lidarContainer.size() * lidarContainer.pointSize());
		else
			throw std::logic_error("Erreur à l'écriture du fichier dans BinaryOneFileUngroupedLidarFileReader::save : le fichier n'existe pas ou n'est pas accessible en écriture ! \n");
	}

	boost::shared_ptr<BinaryPLYArchiLidarFileIO> createBinaryPLYArchiLidarFileReader()
	{
		return boost::shared_ptr<BinaryPLYArchiLidarFileIO>(new BinaryPLYArchiLidarFileIO());
	}

	bool BinaryPLYArchiLidarFileIO::Register()
	{
		//	std::cout << "Format cs : " << cs::DataFormatType(cs::DataFormatType::binary_one_file_ungrouped) << std::endl;
		LidarIOFactory::instance().Register(cs::DataFormatType(cs::DataFormatType::plyarchi), createBinaryPLYArchiLidarFileReader);
		return true;
	}

	BinaryPLYArchiLidarFileIO::BinaryPLYArchiLidarFileIO()
	{}

	bool BinaryPLYArchiLidarFileIO::m_isRegistered = BinaryPLYArchiLidarFileIO::Register();


}
